<?php

namespace App\Containers\AppSection\User\UI\CLI\Commands;

use App\Containers\AppSection\Authorization\Tasks\GetAllRolesTask;
use App\Containers\AppSection\Confirmation\Mails\SendCodeMail;
use App\Containers\AppSection\Confirmation\Tasks\CreateConfirmationTask;
use App\Containers\AppSection\Confirmation\Tasks\DeleteAllConfirmsByValueTask;
use App\Containers\AppSection\User\Actions\RegisterUserWithProfileAction;
use App\Containers\AppSection\User\UI\CLI\Requests\RegisterUserWithProfileRequest;
use App\Ship\Parents\Commands\ConsoleCommand;
use App\Ship\Phones\SmsRu;
use DB;
use Illuminate\Support\Facades\Mail;
use Validator;

class CreateOuterUserCommand extends ConsoleCommand
{
    protected $signature = 'create:outerUser';

    protected $description = 'Create a new Outer User';

    public function handle(): void
    {
        $auto = $this->confirm('Do you want to generate user?');

        $roles = app(GetAllRolesTask::class)->withType('outer')->run(true)->pluck('name')->toArray();
        if (empty($roles)) {
            $this->error('Outer roles missing');
            return;
        }
        if ($auto) {
            $innerRoles = app(GetAllRolesTask::class)->withType('outer')->vacant()->run(true);
            $vacantRoles = array_intersect($roles, $innerRoles->pluck('name')->toArray());
        }
        if (empty($vacantRoles)) {
            $auto = false;
            $this->warn('There are no free roles to generate! Please, enter outer user manually!');
        } else {
            $roles = $vacantRoles;
        }
        $role = $this->choice('Enter the role for this user', $roles);

        switch ($role) {
            case 'borrower':
                $legalForm = $this->choice('Enter the legal form for this user', ['ie', 'entity']);
                break;
            default:
                $legalForm = $this->choice('Enter the legal form for this user', ['ie', 'indiv', 'entity']);
        }

        $fio = $auto ? ucfirst($role) : $this->ask('Enter the fio for this user');

        $email = $auto ? $role . '@incrowd.ru' : $this->ask('Enter the email address of this user');
        $emailCode = $this->sendConfirmation($email, 'email', $auto);
        if ($emailCode === '') {
            return;
        }

        $phone = $auto ? $this->generatePhone() : $this->ask('Enter the phone for this user! +7(___)___-__-__');
        $phoneCode = $this->sendConfirmation($phone, 'phone', $auto);
        if ($phoneCode === '') {
            return;
        }

        $password = $auto ? $role . 'Incrowd' : $this->secret('Enter the password for this user');
        $password_confirmation = $auto ? $password : $this->secret('Please confirm the password');

        if ($password !== $password_confirmation) {
            $this->error('Passwords do not match - exiting!');
            return;
        }

        $request = new RegisterUserWithProfileRequest([
            'fio' => $fio,
            'email' => $email,
            'password' => $password,
            'role' => $role,
            'phone' => $phone,
            'email_code' => $emailCode,
            'phone_code' => $phoneCode,
            'legal_form_type' => $legalForm,
            'without_patronymic' => true,
            'confidentiality_acceptance' => true,
        ]);

        $validator = Validator::make($request->all(), $request->rules());
        if ($validator->fails()) {
            $this->info('Outer User not created. See error messages below:');

            foreach ($validator->errors()->all() as $error) {
                $this->error($error);
            }
            return;
        }

        DB::transaction(function () use ($request) {
            app(RegisterUserWithProfileAction::class)->run($request);
        });

        $this->info('New user - "' . ucfirst($fio) . '" with email - "' . $email . '" was successfully created');

    }

    private function sendConfirmation($value, $type, $auto): string
    {
        $typeConfirm = $type === 'email' ? config('appSection-confirmation.confirms.email.type') : config('appSection-confirmation.confirms.phone.type');
        $code = generateRandomInt(config('appSection-confirmation.code-length'));
        app(DeleteAllConfirmsByValueTask::class)
            ->run(
                $value,
                'register_request',
                $typeConfirm
            );

        $confirmation = app(CreateConfirmationTask::class)
            ->run([
                'code' => $code,
                'value' => $value,
                'request_type' => 'register_request',
                'confirm_type' => $typeConfirm,
            ]);

        if (!$auto && $type === 'email') {
            Mail::send(new SendCodeMail($code, $value));
        }
        if (!$auto && $type === 'phone') {
            SmsRu::create($code)->to($value)->send();
        }

        if ($auto) {
            return $confirmation->code;
        } else {
            $k = 4;
            while ($k > 0) {
                $codeConfirm = $this->ask('Enter the code');
                if ($codeConfirm !== strval($confirmation->code)) {
                    $this->error('Wrong code!');
                    $k--;
                } else {
                    return $codeConfirm;
                }
            }
            if ($k === 0) {
                return '';
            }
        }

        return '';
    }

    private function generatePhone(): string
    {
        return '+7(9' . generateRandomInt(2) . ')' .
            generateRandomInt(3) . '-' .
            generateRandomInt(2) . '-' .
            generateRandomInt(2);
    }
}
